package com.lagou.edu.factory;

import com.lagou.edu.utils.Autowired;
import com.lagou.edu.utils.ClasspathPackageScanner;
import com.lagou.edu.utils.Service;
import com.lagou.edu.utils.StringUtil;
import com.mysql.jdbc.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhoushiduo
 *
 * 工厂类，生产对象（使用反射技术）
 */
public class AnotationBeanFactory {

    /**
     * 任务一：读取解析Anotation，通过反射技术实例化对象并且存储待用（map集合）
     * 任务二：对外提供获取实例对象的接口（根据id获取）
     */

    /**
     * 存储对象
     */
    private static Map<String,Object> map = new HashMap<>();


    static {
        ClasspathPackageScanner classpathPackageScanner = new ClasspathPackageScanner("com.lagou.edu");
        try {
            List<String> classNameList = classpathPackageScanner.getFullyQualifiedClassNameList();
            for (int i = 0; i < classNameList.size(); i++) {
                // 处理每个bean元素，获取到该元素的id 和 class 属性
                String clazz = classNameList.get(i);  // com.lagou.edu.dao.impl.JdbcAccountDaoImpl
                // 通过反射技术实例化对象
                Class<?> aClass = Class.forName(clazz);
                Service annotation = aClass.getAnnotation(Service.class);
                if(null != annotation){
                    String id = annotation.value();
                    Object o = aClass.newInstance();  // 实例化之后的对象
                    // 存储到map中待用
                    map.put(id,o);
                }else{
                    continue;
                }
            }

            for (String key: map.keySet()
                 ) {
                // 调用父元素对象的反射功能
                String parentId = key;
                Object parentObject = map.get(key);
                // 遍历父对象中的所有方法，找到"set" + name
                Field[] fields = parentObject.getClass().getDeclaredFields();
                for (int j = 0; j < fields.length; j++) {
                    Field field = fields[j];
                    Autowired annotation = field.getAnnotation(Autowired.class);
                    if(null != annotation){
                        /*int index = field.getType().getName().lastIndexOf('.');
                        String getter = "set" + field.getType().getName().substring(index +1);
                        Method method = parentObject.getClass().getMethod(getter,field.getType());
                        if(null != method) {
                            // 该方法就是 setAccountDao(AccountDao accountDao)
                            if(StringUtils.isNullOrEmpty(annotation.value())){
                                method.invoke(parentObject, map.get(field.getName()));
                            }else {
                                method.invoke(parentObject, map.get(annotation.value()));
                            }
                        }*/
                        field.setAccessible(true);
                        if(StringUtils.isNullOrEmpty(annotation.value())){
                            field.set(parentObject,map.get(field.getName()));
                        }else {
                            field.set(parentObject,map.get(annotation.value()));
                        }
                        field.setAccessible(false);
                    }
                }

                // 把处理之后的parentObject重新放到map中
                map.put(parentId,parentObject);

            }


        } catch (ClassNotFoundException | NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    // 任务二：对外提供获取实例对象的接口（根据id获取）
    public static  Object getBean(String id) {
        return map.get(id);
    }

}
